package com.junzhiit.nengji.app.web.util.aliyun;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.bainaeco.framework.util.DateUtil;
import com.bainaeco.framework.util.JsonUtil;
import com.junzhiit.nengji.app.web.exception.LimitControlException;
import com.junzhiit.nengji.app.web.exception.MobilePhoneIsExistException;
import com.junzhiit.nengji.app.web.exception.SendSMSFaileException;
import com.junzhiit.nengji.app.web.exception.UserNotFoundException;
import com.junzhiit.nengji.app.web.util.aliyun.bean.SMSParams;
import com.junzhiit.nengji.app.web.vo.ResultVO;
import com.junzhiit.nengji.bo.SendPhoneMessageBO;
import com.junzhiit.nengji.dao.UserDAO;
import com.junzhiit.nengji.dao.cache.UserCacheDAO;
import com.junzhiit.nengji.dao.util.DIYKey;
import com.junzhiit.nengji.model.User;

/**
 * Created on 17/6/7.
 * 短信API产品的DEMO程序,工程中包含了一个SmsDemo类，直接通过
 * 执行main函数即可体验短信产品API功能(只需要将AK替换成开通了云通信-短信产品功能的AK即可)
 * 工程依赖了2个jar包(存放在工程的libs目录下)
 * 1:aliyun-java-sdk-core.jar
 * 2:aliyun-java-sdk-dysmsapi.jar
 *
 * 备注:Demo工程编码采用UTF-8
 */
@Component
public class SmsUtil {

	@Autowired
	private static UserDAO userDAO;

	private static SmsUtil smsUtil;

	@Autowired
	private UserCacheDAO userCacheDAO;

	@PostConstruct
	public void init() {
		smsUtil = this;
		smsUtil.userCacheDAO = this.userCacheDAO;
	}

	private static Log logger = LogFactory.getLog(SmsUtil.class);

	public static final String ALIYUN_SMS_SIGN_NAME = "乐鸽分享链";// 短信签名

	public static final String KEY_VERIFICATION_CODE = "code";// 参数字段名(验证码)

	public static final String KEY_DATE = "date";// 参数字段名(日期)

	public static final String KEY_SEND_MOBLIE_PHONE = "mobilePhone";// 参数字段名(手机号)
	
	public static final String KEY_AUDIT_FAIL_DESCRIPTION="auditFailDescription";//参数字段名(审核不通过描述)

	public static final String ALIYUN_SMS_CONTRACT_EXPIRE = "SMS_135041010";// 合同到期

	public static final String ALIYUN_SMS_SHOP_CLOSE = "SMS_135030981";// 店铺关闭

	public static final String ALIYUN_SMS_TEMPLATE_CODE = "SMS_122225154";// 验证码模板Id

	public static final String ALIYUN_SMS_RETRIEVE_PASSWORD_CODE = "SMS_122225153";// 找回密码

	public static final String ALIYUN_SMS_VALIDATION = "SMS_122225158"; // 验证码通用

	public static final String LIMIT_CONTROL_ERROR = "isv.BUSINESS_LIMIT_CONTROL";// 业务限流异常

	public static final String REMIND_CLOSE_SERVICE = "13326695331";// 提醒商家合同即将到期，续期服务热线

	public static final String SHOP_CLOSE_SERVICE = "13326695331";// 提醒商家店铺已到期，续期服务热线

	public static final String SHOP_MERCHANTS_AUDIT_SUCCESS = "SMS_137411191";// 店铺审核通过信息提醒

	public static final String SHOP_MERCHANTS_AUDIT_FAIL = "SMS_137416315";// 店铺审核不通过信息提醒

	public static final String SHOPS_MERCHANTS_AUDIT_SUCCESS = "SMS_137416171";// 品牌审核通过信息提醒

	public static final String SHOPS_MERCHANTS_AUDIT_FAIL = "SMS_137426271";// 品牌审核不通过信息提醒
	
	public static final String GOODS_REFUND_AUDIT_SUCCESS="SMS_142149368";//申请退货审核通过,请于当日之内申请退款时效提醒
	
	public static final String GOODS_REFUND_AUDIT_FAIL="SMS_142149372";//申请退货审核不通过,请于当日之内再次申请退货时效提醒
	
	public static final String ORDERS_REFUND_AUDIT_FAIL="SMS_142149375";//申请退款审核不通过,请于当日之内再次申请退款时效提醒

	// 产品名称:云通信短信API产品,开发者无需替换
	static final String product = "Dysmsapi";
	// 产品域名,开发者无需替换
	static final String domain = "dysmsapi.aliyuncs.com";

	// TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
	static final String accessKeyId = "LTAIwFph5r7OgGAy";

	static final String accessKeySecret = "bGsbPJEmXy2Qo8X5YcxGWRgZ9taaAn";

	public static SendSmsResponse sendSms(SMSParams smsParams) throws ClientException {

		StringBuilder params = new StringBuilder();
		//有验证码--eg:绑定银行卡
		if (smsParams.getParamValues() != null) {
			params.append("{");
			for (int i = 0; i < smsParams.getParamKeys().length; i++) {
				if (i > 0)
					params.append(",");
				params.append(smsParams.getParamKeys()[i]).append(":").append("\"" + smsParams.getParamValues()[i] + "\"");
			}
			params.append("}");
		}
		//有描述--eg:审核不通过
		if(smsParams.getAuditFailDescription()!=null){
			params.append("{");
			for (int i = 0; i < smsParams.getParamKeys().length; i++) {
				if (i > 0)
					params.append(",");
				params.append(smsParams.getParamKeys()[i]).append(":").append("\"" + smsParams.getAuditFailDescription()[i] + "\"");
			}
			params.append("}");
		}
		//无验证码无描述--eg:审核通过
		if(smsParams.getParamValues()==null&&smsParams.getAuditFailDescription()==null){
			params.append("{");
			for (int i = 0; i < smsParams.getParamKeys().length; i++) {
				if (i > 0)
					params.append(",");
				params.append(smsParams.getParamKeys()[i]).append(":")
				.append("\"" + smsParams.getPhoneNumbers()[i] + "\"");
			}
			params.append("}");
		}
		
		StringBuilder phone = new StringBuilder();
		for (int i = 0; i < smsParams.getPhoneNumbers().length; i++) {
			if (i > 0)
				phone.append(",");
			phone.append(smsParams.getPhoneNumbers()[i]);
		}

		// 可自助调整超时时间
		System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
		System.setProperty("sun.net.client.defaultReadTimeout", "10000");

		// 初始化acsClient,暂不支持region化
		IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
		DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
		IAcsClient acsClient = new DefaultAcsClient(profile);

		// 组装请求对象-具体描述见控制台-文档部分内容
		SendSmsRequest request = new SendSmsRequest();

		// 必填:待发送手机号
		request.setPhoneNumbers(phone.toString());
		// 必填:短信签名-可在短信控制台中找到
		request.setSignName(smsParams.getSignName());
		// 必填:短信模板-可在短信控制台中找到
		request.setTemplateCode(smsParams.getTemplateCode());
		// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的,您的验证码为${code}"时,此处的值为
		request.setTemplateParam(params.toString());

		if (StringUtils.isNotBlank(smsParams.getOutId())) {
			// 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
			request.setOutId(smsParams.getOutId());
		}

		// hint 此处可能会抛出异常，注意catch
		SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
		// hint 此处可能会抛出异常，注意catch
		logger.info("短信接口返回的数据 Start --手机号码---" + phone.toString() + "---------");
		logger.info(JsonUtil.toJson(sendSmsResponse));
		logger.info("短信接口返回的数据End   ----------------");
		return sendSmsResponse;
	}

	public static Boolean sendSmsToBoolean(SMSParams smsParams) throws ClientException {
		SendSmsResponse response = SmsUtil.sendSms(smsParams);
		if (response.getCode() != null && response.getCode().equals("OK")) {
			return true;
		} else {
			return false;
		}
	}

	public static QuerySendDetailsResponse querySendDetails(String bizId, String phoneNumbers) throws ClientException {

		// 可自助调整超时时间
		System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
		System.setProperty("sun.net.client.defaultReadTimeout", "10000");

		// 初始化acsClient,暂不支持region化
		IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
		DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
		IAcsClient acsClient = new DefaultAcsClient(profile);

		// 组装请求对象
		QuerySendDetailsRequest request = new QuerySendDetailsRequest();
		// 必填-号码
		request.setPhoneNumber(phoneNumbers);
		// 可选-流水号
		request.setBizId(bizId);
		// 必填-发送日期 支持30天内记录查询，格式yyyyMMdd
		SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
		request.setSendDate(ft.format(new Date()));
		// 必填-页大小
		request.setPageSize(10L);
		// 必填-当前页码从1开始计数
		request.setCurrentPage(1L);

		// hint 此处可能会抛出异常，注意catch
		QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);

		return querySendDetailsResponse;
	}

	public static void main(String[] args) throws ClientException, InterruptedException {
		String[] phoneNumbers = { "13800138000" };
		String[] paramKeys = { "code" };
		String[] paramValues = { "000456" };
		SMSParams smsParams = new SMSParams();
		smsParams.setSignName(SmsUtil.ALIYUN_SMS_SIGN_NAME);
		smsParams.setTemplateCode(SmsUtil.ALIYUN_SMS_TEMPLATE_CODE);
		smsParams.setPhoneNumbers(phoneNumbers);
		smsParams.setParamKeys(paramKeys);
		smsParams.setParamValues(paramValues);
		// smsParams.setOutId("");

		SendSmsResponse response = sendSms(smsParams);
		System.out.println("短信接口返回的数据----------------");
		System.out.println("Code=" + response.getCode());
		System.out.println("Message=" + response.getMessage());
		System.out.println("RequestId=" + response.getRequestId());
		System.out.println("BizId=" + response.getBizId());

		Thread.sleep(3000L);

		// 查明细
		if (response.getCode() != null && response.getCode().equals("OK")) {
			QuerySendDetailsResponse querySendDetailsResponse = querySendDetails(response.getBizId(), "13760093574");
			System.out.println("短信明细查询接口返回数据----------------");
			System.out.println("Code=" + querySendDetailsResponse.getCode());
			System.out.println("Message=" + querySendDetailsResponse.getMessage());
			int i = 0;
			for (QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO : querySendDetailsResponse
					.getSmsSendDetailDTOs()) {
				System.out.println("SmsSendDetailDTO[" + i + "]:");
				System.out.println("Content=" + smsSendDetailDTO.getContent());
				System.out.println("ErrCode=" + smsSendDetailDTO.getErrCode());
				System.out.println("OutId=" + smsSendDetailDTO.getOutId());
				System.out.println("PhoneNum=" + smsSendDetailDTO.getPhoneNum());
				System.out.println("ReceiveDate=" + smsSendDetailDTO.getReceiveDate());
				System.out.println("SendDate=" + smsSendDetailDTO.getSendDate());
				System.out.println("SendStatus=" + smsSendDetailDTO.getSendStatus());
				System.out.println("Template=" + smsSendDetailDTO.getTemplateCode());
			}
			System.out.println("TotalCount=" + querySendDetailsResponse.getTotalCount());
			System.out.println("RequestId=" + querySendDetailsResponse.getRequestId());
		}
	}

	/**
	 * 
	 * TODO 根据用户ID查询手机号码,发送短信
	 * 
	 * @author PeterMo
	 * @time 2018年5月29日 下午2:43:20
	 * @return ResultVO
	 */
	public static ResultVO sendPhoneCodeByUserId(String userId, String smsModel) {
		User user = userDAO.query(userId);
		if (user == null) {
			throw new UserNotFoundException("用户未找到");
		}
		String mobilePhone = user.getMobilePhone();

		ResultVO result = new ResultVO();
		String key = DIYKey.getMobilePhoneCodeKey(mobilePhone);
		String randCode = RandomStringUtils.randomNumeric(6);
		SMSParams sms = new SMSParams();
		sms.setSignName(ALIYUN_SMS_SIGN_NAME);
		sms.setTemplateCode(smsModel);
		sms.setPhoneNumbers(new String[] { mobilePhone });
		sms.setParamKeys(new String[] { KEY_VERIFICATION_CODE });
		sms.setParamValues(new String[] { randCode });
		boolean sendSucceed = false;
		try {
			SendSmsResponse response = sendSms(sms);
			if (response.getCode() != null && response.getCode().equals("OK")) {
				sendSucceed = true;
			} else if (response.getCode() != null && response.getCode().equals(SmsUtil.LIMIT_CONTROL_ERROR)) {
				throw new LimitControlException("不能过于频繁发送验证码,请稍后再发");
			}
		} catch (ClientException e) {
			e.printStackTrace();
		}
		if (sendSucceed) {
			// 设置验证码有效时间为10分钟
			Date date = DateUtil.addMins(new Date(), 10);
			SmsUtil.RandCode code = new SmsUtil.RandCode();
			code.setCode(randCode);
			code.setTimestamp(date.getTime());
			smsUtil.userCacheDAO.addHash(key, code);
		} else {
			throw new SendSMSFaileException("无法发送手机验证码");
		}
		return result;
	}

	/**
	 * 
	 * TODO 根据用户手机号码发送短信
	 * 
	 * @author PeterMo
	 * @time 2018年5月29日 下午2:43:20
	 * @return ResultVO
	 */
	public static ResultVO sendPhoneCode(String mobilePhone, String smsModel) {
		ResultVO result = new ResultVO();
		String key = DIYKey.getMobilePhoneCodeKey(mobilePhone);
		String randCode = RandomStringUtils.randomNumeric(6);
		SMSParams sms = new SMSParams();
		sms.setSignName(ALIYUN_SMS_SIGN_NAME);
		sms.setTemplateCode(smsModel);
		sms.setPhoneNumbers(new String[] { mobilePhone });
		sms.setParamKeys(new String[] { KEY_VERIFICATION_CODE });
		sms.setParamValues(new String[] { randCode });
		boolean sendSucceed = true;
		try {
			SendSmsResponse response = sendSms(sms);
			if (response.getCode() != null && response.getCode().equals("OK")) {
				sendSucceed = true;
			} else if (response.getCode() != null && response.getCode().equals(SmsUtil.LIMIT_CONTROL_ERROR)) {
				throw new LimitControlException("不能过于频繁发送验证码,请稍后再发");
			}
		} catch (ClientException e) {
			e.printStackTrace();
		}
		if (sendSucceed) {
			// 设置验证码有效时间为10分钟
			Date date = DateUtil.addMins(new Date(), 10);
			SmsUtil.RandCode code = new SmsUtil.RandCode();
			code.setCode(randCode);
			code.setTimestamp(date.getTime());
			smsUtil.userCacheDAO.addHash(key, code);
		} else {
			throw new SendSMSFaileException("无法发送手机验证码");
		}
		return result;
	}

	/**
	 * 
	 * TODO
	 * 
	 * @author PeterMo
	 * @time 2018年5月29日 下午2:49:31
	 * @return ResultVO
	 */
	public static ResultVO sendPhoneCodeByUserId(String userId, String mobilePhone, String smsModel) {
		ResultVO result = new ResultVO();

		User user = userDAO.query(userId);
		if (user == null) {
			throw new UserNotFoundException("用户没找到");
		}

		User param = userDAO.checkMobilePhone(mobilePhone);
		if (param != null) {
			String phone = user.getMobilePhone();
			if (!StringUtils.isNotBlank(phone) || (StringUtils.isNotBlank(phone) && !phone.equals(mobilePhone))) {
				throw new MobilePhoneIsExistException("号码已被使用");
			}
		}

		String randCode = RandomStringUtils.randomNumeric(6);

		SMSParams sms = new SMSParams();
		sms.setSignName(ALIYUN_SMS_SIGN_NAME);
		sms.setTemplateCode(smsModel);
		sms.setPhoneNumbers(new String[] { mobilePhone });
		sms.setParamKeys(new String[] { SmsUtil.KEY_VERIFICATION_CODE });
		sms.setParamValues(new String[] { randCode });

		boolean sendSucceed = false;
		try {
			SendSmsResponse response = SmsUtil.sendSms(sms);
			if (response.getCode() != null && response.getCode().equals("OK")) {
				sendSucceed = true;
			}
		} catch (ClientException e) {
			e.printStackTrace();
		}
		if (sendSucceed) {
			// 设置验证码有效时间为10分钟
			Date time = DateUtil.addMins(new Date(), 10);

			SmsUtil.RandCode code = new SmsUtil.RandCode();
			code.setCode(randCode);
			code.setTimestamp(time.getTime());

			String key = DIYKey.getMobilePhoneCodeKey(mobilePhone);
			result.setData(smsUtil.userCacheDAO.addHash(key, code));
		} else {
			throw new SendSMSFaileException("发送手机验证码失败");
		}
		return result;
	}

	public static class RandCode {

		private String code;

		private Long timestamp;

		public String getCode() {
			return code;
		}

		public void setCode(String code) {
			this.code = code;
		}

		public Long getTimestamp() {
			return timestamp;
		}

		public void setTimestamp(Long timestamp) {
			this.timestamp = timestamp;
		}
	}

	/**
	 * 
	 * TODO 根据手机号码发短信提醒
	 * 
	 * @author Harry
	 * @time 2018年7月4日 上午9:26:31
	 * @return ResultVO
	 */
	public static ResultVO sendPhoneMessage(SendPhoneMessageBO spmb) {
		ResultVO result = new ResultVO();
		SMSParams sms = new SMSParams();
		sms.setPhoneNumbers(new String[] { spmb.getMobilePhone() });
		sms.setSignName(ALIYUN_SMS_SIGN_NAME);
		sms.setTemplateCode(spmb.getSmsModel());
		if (spmb.getAuditFailDescription() != null) {
			sms.setParamKeys(new String[] { KEY_AUDIT_FAIL_DESCRIPTION });
			sms.setAuditFailDescription(new String[] { spmb.getAuditFailDescription() });
		}else{
			sms.setParamKeys(new String[]{KEY_SEND_MOBLIE_PHONE});
		}
		Boolean sendSucced = false;
		try {
			SendSmsResponse response = sendSms(sms);
			if (response.getCode() != null && response.getCode().equals("OK")) {
				sendSucced = true;
			}
			if (response.getCode() != null && response.getCode().equals(SmsUtil.LIMIT_CONTROL_ERROR)) {
				throw new LimitControlException("不能过于频繁发送验证码,请稍后再发");
			}
		} catch (ClientException e) {
			e.printStackTrace();
		}
		if (!sendSucced) {
			throw new SendSMSFaileException("无法发送手机验证码");
		}
		return result;
	}
}